﻿package mess;


import java.awt.FontMetrics;

import media.*;
import core.*;
import scrn.*;


// ======================================= Выполняет разбивку сообщений на блоки
public final class MessPars {

//==================================================================== Константы
private static final int Q_LEN = 16; // Начальная длина очереди
private static final int Q_INC = 16; // Добавляемая длина очереди

//=================================================================== Переменные
public int hTot = 0; // Общая высота сообщения в точках
public int[] res = new int[Q_LEN]; // Результат разметки
private int resP = 0; // Указатель на своб. слот массива результатов
public int rTot = 0; // Кол-во строк в сообщении
private int width = 128; // Ширина поля сообщений
private int timeW; // Ширина часов в сообщении
private int point; // Текущая точка
private int rH; // Высота строки
private int[] resRow = new int[Q_LEN]; // Результат разметки строки
private int resRowP = 0; // Указатель на своб. слот массива разметки строки
private String text; // Текст, добавляемый в данный момент


//================================================================ Инициализация
public MessPars() {

}


// ====================================================== Добавление блока ников
public void addNicks(String nicks) {

	text = nicks;
	pText(Message.B_NICKS);
}


//============================================================ Добавление текста
public void addText(String text) {

	this.text = text;
	pText(Message.B_TEXT);
}


//===================================================== Добавление блока времени
public void addTime() {

	pBlock(Message.B_TIME);
	if (rH < Draw.fontClkH) {
		rH = Draw.fontClkH;
	}
	point += timeW;
}


// ================================================== Вернуть результат разметки
public int[] getRes() {

	if (point != 0) {
		writeRow();
	}
	int[] retRes = new int[resP];
	System.arraycopy(res, 0, retRes, 0, resP);
	return retRes;
}


//=============================== Увеличение размера массива результата разметки
private void inc(int how) {

	int[] newRes = new int[res.length + Math.max(how, Q_INC)];
	System.arraycopy(res, 0, newRes, 0, res.length);
	res = newRes;
	newRes = null;
	Mess.m("MessPars.inc", "Новая длина массива результатов: " + res.length);
}


//=================================== Увеличение размера массива разметки строки
private void incRow() {

	int[] newRes = new int[resRow.length + Q_INC];
	System.arraycopy(resRow, 0, newRes, 0, resRow.length);
	resRow = newRes;
	newRes = null;
	Mess.m("MessPars.incRow", "Новая длина массива строки: " + resRow.length);
}


//=================================================== Добавить обозначение блока
private void pBlock(int blockType) {

	if (resRowP >= resRow.length) {
		incRow();
	}
	resRow[resRowP++] = blockType;
}


//============================================================== Разметка текста
private void pText(int blockType) {

	int bp = 0; // Указатель на начало блока разметки
	int ch; // Текущий символ
	int ep = 0; // Указатель на конец блока разметки
	int smlW = 0; // Ширина смайла
	int smlH = 0; // Высота смайла
	char[] textCh = text.toCharArray();

	try {
		FontMetrics fontMessMetr = Draw.getFontMetrics(Draw.fontMess);
		int textLen = text.length(); // Общая длина текста

		do { // Основной цикл
			ch = text.charAt(ep);
			if ((ch < 32) || (ch == ResMan.CHAR)) { // --------- Служебный символ
				if (bp != ep) {
					writeTextBlock(blockType, bp, ep - 1,
							fontMessMetr.charsWidth(textCh, bp, ep - bp));
				}

				switch (ch) {
				case ResMan.CHAR: // Встречен смайл

					int id = 0;

					while ((++ep < textLen) && ((ch = text.charAt(ep)) >= '0')
							&& ch <= '9') {
						id = (id << 3) + id + id + ch - 0x30;
					}

					--ep; // Смайл завершен, но мы прочитали следующий символ. Возвращаем его.

					Pic sml = (Pic) Man.resMan.getRes(new Long(id));

					smlH = sml.h;
					smlW = sml.w;
					if ((point + smlW) > width) { // Смайл не влазит
						writeRow();
					}
					writeSmile(id, smlW, smlH);
					break;

				case '\n': // Встречен перевод строки
					writeRow();
					break;

				case '\t': // Встречен табулятор

					// TODO Придумать алгоритм расчета позиций табуляторов
					break;

				default: // Встречен неизвестный управляющий символ
					Mess.m("MessPars.parseText", "В сообщении неизвестный символ: "
							+ (char) ch + "(код " + ch + ")");
					break;

				}

				ep++;
				bp = ep;
			} else { // ----------------------------- Текстовый символ
				if ((point + fontMessMetr.charsWidth(textCh, bp, ep - bp + 1)) >= width) { // Не влазит в строку
					writeTextBlock(blockType, bp, ep - 1,
							fontMessMetr.charsWidth(textCh, bp, ep - bp));
					writeRow();
					bp = ep;
				} else {
					ep++;
				}
			}

		} while (ep < textLen);

		if (bp != ep) {
			writeTextBlock(blockType, bp, ep - 1,
					fontMessMetr.charsWidth(textCh, bp, ep - bp));
		}

	} catch (Exception e) {
		Mess.err("MessPars.parseText", "Ошибка разметки", e);
	}

}


// ===================================================== Записать текстовый блок
private void writeTextBlock(int blockType, int bp, int ep, int textWidth) {

	if (resRowP + 4 >= resRow.length) {
		incRow();
	}

	resRow[resRowP++] = blockType;
	resRow[resRowP++] = bp;
	resRow[resRowP++] = ep;
	resRow[resRowP++] = textWidth;

	if (rH < Draw.fontMessH) {
		rH = Draw.fontMessH;
	}

	point += textWidth;
}


// ============================================================= Записать строку
private void writeRow() {

	if (resP + resRowP + 3 >= res.length) {
		inc(resP + resRowP + 3 - res.length);
	}
	// FIXME Убрать лишнюю информацию из записи строки

	if (rH < Draw.fontMessH) {
		rH = Draw.fontMessH;
	}

	res[resP++] = resRowP + 2; // Длина байтов строки
	res[resP++] = rH; // Высота строки
	System.arraycopy(resRow, 0, res, resP, resRowP);
	resP += resRowP;
	res[resP++] = resRowP + 2;

	hTot += rH;
	rTot++;

	resRowP = 0;
	rH = 0;
	point = 0;
}


// ============================================================== Записать смайл
private void writeSmile(int ind, int smileWidth, int smileHeight) {

	if (resRowP + 3 >= resRow.length) {
		incRow();
	}

	resRow[resRowP++] = Message.B_SMILE;
	resRow[resRowP++] = ind;

	if (rH < smileHeight) {
		rH = smileHeight;
	}

	point += smileWidth;
}


//======================================================================== Сброс
public void reset(int width) {

	resP = 0;
	rH = 0;
	hTot = 0;
	rTot = 0;
	point = 0;
	resRowP = 0;
	timeW = Draw.timeMessW + Draw.timeMessOff;
	this.width = width;
}


//================================================================ Ширина строки
public void setWidth(int width) {

	this.width = width;
}

}
